Add a Target to the build script deps key
authorAlex Crichton <alex@alexcrichton.com>
Wed, 1 Jul 2015 17:37:21 +0000 (10:37 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 1 Jul 2015 17:37:21 +0000 (10:37 -0700)
Previously a Target was not considered to be in the key of the map to build
script dependencies, but this meant that information like whether it was a
dev-dependency was lost. As a result libraries would depend on the build scripts
of their dev-dependencies, causing an internal error when the build script
hadn't finished yet when the library was being built.

Closes #1751

src/cargo/ops/cargo_rustc/context.rs
src/cargo/ops/cargo_rustc/custom_build.rs
src/cargo/ops/cargo_rustc/mod.rs
tests/test_cargo_test.rs

index 6429427228379607884c96b7deba882d611f95ca..26b4a14c079b27dbbf798d867bf5f6031eb28c54 100644 (file)
@@ -36,7 +36,7 @@ pub struct Context<'a, 'cfg: 'a> {
                               Fingerprint>,
     pub compiled: HashSet<(&'a PackageId, &'a Target, &'a Profile)>,
     pub build_config: BuildConfig,
-    pub build_scripts: HashMap<(&'a PackageId, Kind, &'a Profile),
+    pub build_scripts: HashMap<(&'a PackageId, &'a Target, &'a Profile, Kind),
                                Vec<&'a PackageId>>,
 
     host: Layout,
index acf9788aef1fcd4c7ae6247243e07eabd5937fb3..b2c98a41b724e723423450d97e739b1c90858091 100644 (file)
@@ -103,7 +103,8 @@ pub fn prepare(pkg: &Package, target: &Target, req: Platform,
     let id = pkg.package_id().clone();
     let all = (id.clone(), pkg_name.clone(), build_state.clone(),
                build_output.clone());
-    let plugin_deps = super::load_build_deps(cx, pkg, profile, Kind::Host);
+    let plugin_deps = super::load_build_deps(cx, pkg, target, profile,
+                                             Kind::Host);
 
     try!(fs::create_dir_all(&cx.layout(pkg, Kind::Target).build(pkg)));
     try!(fs::create_dir_all(&cx.layout(pkg, Kind::Host).build(pkg)));
@@ -349,7 +350,7 @@ impl BuildOutput {
 /// targets/profiles which are being built.
 pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>,
                            pkg: &'b Package,
-                           targets: &[(&Target, &'b Profile)]) {
+                           targets: &[(&'b Target, &'b Profile)]) {
     let mut ret = HashMap::new();
     for &(target, profile) in targets {
         build(&mut ret, Kind::Target, pkg, target, profile, cx);
@@ -357,21 +358,22 @@ pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>,
     }
 
     // Make the output a little more deterministic by sorting all dependencies
-    for (&(id, kind, _), slot) in ret.iter_mut() {
+    for (&(id, target, _, kind), slot) in ret.iter_mut() {
         slot.sort();
         slot.dedup();
-        debug!("script deps: {}/{:?} => {:?}", id, kind,
+        debug!("script deps: {}/{}/{:?} => {:?}", id, target.name(), kind,
                slot.iter().map(|s| s.to_string()).collect::<Vec<_>>());
     }
     cx.build_scripts = ret;
 
     // Recursive function to build up the map we're constructing. This function
     // memoizes all of its return values as it goes along.
-    fn build<'a, 'b, 'cfg>(out: &'a mut HashMap<(&'b PackageId, Kind, &'b Profile),
+    fn build<'a, 'b, 'cfg>(out: &'a mut HashMap<(&'b PackageId, &'b Target,
+                                                 &'b Profile, Kind),
                                                 Vec<&'b PackageId>>,
                            kind: Kind,
                            pkg: &'b Package,
-                           target: &Target,
+                           target: &'b Target,
                            profile: &'b Profile,
                            cx: &Context<'b, 'cfg>)
                            -> &'a [&'b PackageId] {
@@ -381,8 +383,8 @@ pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>,
         // dependencies.
         let kind = if target.for_host() {Kind::Host} else {kind};
         let id = pkg.package_id();
-        if out.contains_key(&(id, kind, profile)) {
-            return &out[&(id, kind, profile)]
+        if out.contains_key(&(id, target, profile, kind)) {
+            return &out[&(id, target, profile, kind)]
         }
 
         // This loop is both the recursive and additive portion of this
@@ -416,7 +418,7 @@ pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>,
             }
         }
 
-        let prev = out.entry((id, kind, profile)).or_insert(Vec::new());
+        let prev = out.entry((id, target, profile, kind)).or_insert(Vec::new());
         prev.extend(ret);
         return prev
     }
index db5d0436b8f601a7b675f0a6bcd454a1450cc19f..486ce8d5c899c8ed0b4a4040926adadba5e56f6a 100644 (file)
@@ -331,7 +331,7 @@ fn rustc(package: &Package, target: &Target, profile: &Profile,
     let rustcs = try!(prepare_rustc(package, target, profile, crate_types,
                                     cx, req));
 
-    let plugin_deps = load_build_deps(cx, package, profile, Kind::Host);
+    let plugin_deps = load_build_deps(cx, package, target, profile, Kind::Host);
 
     return rustcs.into_iter().map(|(mut rustc, kind)| {
         let name = package.name().to_string();
@@ -352,7 +352,8 @@ fn rustc(package: &Package, target: &Target, profile: &Profile,
         let build_state = cx.build_state.clone();
         let current_id = package.package_id().clone();
         let plugin_deps = plugin_deps.clone();
-        let mut native_lib_deps = load_build_deps(cx, package, profile, kind);
+        let mut native_lib_deps = load_build_deps(cx, package, target, profile,
+                                                  kind);
         if package.has_custom_build() && !target.is_custom_build() {
             native_lib_deps.insert(0, current_id.clone());
         }
@@ -384,9 +385,9 @@ fn rustc(package: &Package, target: &Target, profile: &Profile,
             // dynamic library load path as a plugin's dynamic library may be
             // located somewhere in there.
             let build_state = build_state.outputs.lock().unwrap();
-            add_native_deps(&mut rustc, &*build_state, native_lib_deps,
+            add_native_deps(&mut rustc, &build_state, native_lib_deps,
                             kind, pass_l_flag, &current_id);
-            try!(add_plugin_deps(&mut rustc, &*build_state, plugin_deps));
+            try!(add_plugin_deps(&mut rustc, &build_state, plugin_deps));
             drop(build_state);
 
             // FIXME(rust-lang/rust#18913): we probably shouldn't have to do
@@ -456,10 +457,10 @@ fn rustc(package: &Package, target: &Target, profile: &Profile,
     }
 }
 
-fn load_build_deps(cx: &Context, pkg: &Package,
+fn load_build_deps(cx: &Context, pkg: &Package, target: &Target,
                    profile: &Profile, kind: Kind) -> Vec<PackageId> {
     let pkg = cx.get_package(pkg.package_id());
-    cx.build_scripts.get(&(pkg.package_id(), kind, profile)).map(|deps| {
+    cx.build_scripts.get(&(pkg.package_id(), target, profile, kind)).map(|deps| {
         deps.iter().map(|&d| d.clone()).collect::<Vec<_>>()
     }).unwrap_or(Vec::new())
 }
index 91304272a3c8dfd01e187cc806e379b2687b28d6..268355179b360454b0b9380d6d302ff93d0188a8 100644 (file)
@@ -1631,3 +1631,29 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
 
 ", compiling = COMPILING, running = RUNNING, doctest = DOCTEST)))
 });
+
+test!(dev_dep_with_build_script {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+
+            [dev-dependencies]
+            bar = { path = "bar" }
+        "#)
+        .file("src/lib.rs", "")
+        .file("examples/foo.rs", "fn main() {}")
+        .file("bar/Cargo.toml", r#"
+            [package]
+            name = "bar"
+            version = "0.0.1"
+            authors = []
+            build = "build.rs"
+        "#)
+        .file("bar/src/lib.rs", "")
+        .file("bar/build.rs", "fn main() {}");
+    assert_that(p.cargo_process("test"),
+                execs().with_status(0));
+});